#include "parse_stream.h"
#include <sstream>

// is this the end of a line
int _is_eol(char const * text) {
	if (text[0] == 0)
		return 1;
	if (text[0] == '\r' && text[1] == '\n')
		return 2;
	return 0;
}
// ctor
parse_stream_c::parse_stream_c(char const * text) 
	: var_data(text, text + strlen(text) + 1)  // note +1 for null terminator
	, var_position(0) {
}
// ctor
parse_stream_c::parse_stream_c() 
	: var_position(0) {
}
// set our text
void parse_stream_c::begin_text(char const * text) {
	var_data.clear();
	var_data.insert(var_data.begin(), text, text + strlen(text) + 1);
	var_position = 0;
}
// set our text
void parse_stream_c::begin_file(char const * path) {
	FILE * file;
	if (0 != fopen_s(&file, path, "rb"))
		throw new std::exception("couldn't open file");

	fseek(file, 0, SEEK_END);
	long pos = ftell(file);
	fseek(file, 0, SEEK_SET);

	var_data.reserve(pos + 1);
	var_data.resize(pos);
	if (1 != fread(&var_data[0], pos, 1, file))
		throw new std::exception("file error");
	var_data.push_back(0);

	var_position = 0;
}
// check if the stream starts with something
int parse_stream_c::starts(char const * text) const {
	int len = strlen(text);
	return 0 == strncmp(&var_data[var_position], text, len)
		? len
		: 0;
}
// check if the stream starts with a space
int parse_stream_c::starts_space() const {
	return var_data[var_position] == ' '
		|| var_data[var_position] == '\t';
}
// try to read a token
bool parse_stream_c::try_read(char const * text) {
	if (auto len = starts( text )) {
		advance(len);
		return true;
	}
	return false;
}
// read a line
std::string parse_stream_c::read_line() {
	// if we're starting on an eol skip it
	if (int eol_len = _is_eol(&var_data[var_position]))
		advance(eol_len);

	int pos = var_position;
	while (!_is_eol(&var_data[pos])) {
		++pos;
	}
	auto res = std::string(var_data.begin() + var_position, var_data.begin() + pos);
	var_position = pos;
	return res;
}
// read a single character
char parse_stream_c::read_char() {
	char res = var_data[var_position];
	advance(1);
	return res;
}
// advance the stream
int parse_stream_c::advance(int characters) {
	int old_pos = var_position;
	var_position += characters;
	if (var_position >= int(var_data.size()))
		var_position = var_data.size() - 1;
	return var_position - old_pos;
}
// do we have more data availible 
bool parse_stream_c::more() const {
	return var_position != var_data.size() - 1;
}